package com.lse_api.utils.pdfutil;

import cn.hutool.core.codec.Base64Encoder;
import com.itextpdf.text.*;
import com.itextpdf.text.pdf.BaseFont;
import com.itextpdf.text.pdf.PdfDiv;
import com.itextpdf.text.pdf.PdfWriter;
import com.itextpdf.tool.xml.XMLWorkerHelper;
import com.lse_api.utils.pdfutil.stringutil.StringUtils;
import freemarker.template.Configuration;
import freemarker.template.Template;
import lombok.extern.slf4j.Slf4j;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.rendering.PDFRenderer;
import org.xhtmlrenderer.pdf.ITextRenderer;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.*;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;

/**
 * PDF工具类 主要用于生成PDF
 * 依赖包: itextpdf,
 * itext-asian,
 * xmlworker,
 * freemarker,
 * flying-saucer-pdf,
 * pdfbox,
 * maven中央库搜索即可
 *
 * @author 祁雪
 */
@Slf4j
public class PDFUtil {

    public static Configuration configuration = null;

    /**
     * 生成PDF 可传入HTML代码片段与普通文字
     *
     * @param outPath  输出路径
     * @param fileName 文件名称
     * @param title    标题
     * @param content  内容
     */
    public static void createPdf(String outPath, String fileName,
                                 String title, String content) {

        if (StringUtils.isEmpty(outPath) ||
                StringUtils.isEmpty(fileName)) {
            log.warn("Please enter the import path and file name");
            return;
        }
        File file = new File(outPath, fileName);
        try (
                FileOutputStream fileOutputStream = new FileOutputStream(file);
        ) {
            Document document = new Document();

            /*Rectangle pageSize = new Rectangle(PageSize.A4.getHeight(), PageSize.A4.getWidth());

            document.setPageSize(pageSize);*/


            PdfWriter pdfWriter = PdfWriter.getInstance(document, fileOutputStream);
            pdfWriter.setViewerPreferences(PdfWriter.PageModeUseThumbs);

            document.open();

            // 添加标题
            ByteArrayInputStream byteArrayInputStream = null;
            if (!StringUtils.isEmpty(title)) {
                title = "<h1 style='width:100%;text-align:center;'>" + title + "</h1>";

                byteArrayInputStream = new ByteArrayInputStream(title.getBytes());

                XMLWorkerHelper.getInstance().parseXHtml(pdfWriter, document,
                        byteArrayInputStream, Charset.forName("UTF-8"), new ChinaFont(16, Font.BOLD));
            }

            // 添加内容
            content = "<div>" + content + "</div>";

            byteArrayInputStream = new ByteArrayInputStream(content.getBytes());

            XMLWorkerHelper.getInstance().parseXHtml(pdfWriter, document,
                    byteArrayInputStream, Charset.forName("UTF-8"), new ChinaFont());

            byteArrayInputStream.close();

            document.close();

            pdfWriter.close();

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 根据FTL模板导出PDF
     * 注: 先调用模板配置后再调用此方法
     *
     * @param ftlPath       ftl模板文件夹路径
     * @param ftlName       ftl模板名称
     * @param imageDiskPath PDF内图片存储路径
     * @param data          数据
     * @param outputFile    输出路径 含文件夹名称
     * @throws Exception
     */
    public static void generateToFile(String ftlPath, String ftlName,
                                      String imageDiskPath, Object data,
                                      String outputFile) throws Exception {

        ITextRenderer render = new ITextRenderer();

        try (
                OutputStream out = new FileOutputStream(outputFile)
        ) {

            String html = getHtmlContent(ftlName, data);    //组装模板和数据生成html串

            if (html == null) {
                throw new RuntimeException("模板文件异常或未加载模板");
            }

            render = getRender(ftlPath);

            render.setDocumentFromString(html);        //此处抛异常

            if (!StringUtils.isEmpty(imageDiskPath)) {

                // html中如果有图片，图片的路径则使用这里设置的路径的相对路径，这个是作为根路径
                System.out.println("设置图片路径");
                render.getSharedContext().setBaseURL("file:/" + imageDiskPath);

            }

            render.layout();

            render.createPDF(out);

            render.finishPDF();

        } catch (Exception e) {
            e.printStackTrace();

        }

    }

    /**
     * 使用freemarker得到html内容
     *
     * @param ftlName ftl模板名称
     * @param o
     * @return
     * @throws Exception
     */
    public static String getHtmlContent(String ftlName, Object o) throws Exception {

        String html = null;
        if (configuration == null) {
            return null;
        }

        Template tpl = configuration.getTemplate(ftlName);

        tpl.setEncoding("UTF-8");

        StringWriter writer = new StringWriter();

        tpl.process(o, writer);

        writer.flush();

        html = writer.toString();

        writer.close();

        return html;

    }


    /**
     * 获取Freemarker配置
     *
     * @param templatePath 模板文件路径 不包含文件名称
     * @return
     * @throws IOException
     */

    public static void getFreemarkerConfig(String templatePath) throws IOException {

        Configuration config = new Configuration();

        config.setDirectoryForTemplateLoading(new File(templatePath));

        config.setEncoding(Locale.CHINA, "utf-8");
        config.setDateTimeFormat("yyyy-MM-dd HH:mm:ss");

        configuration = config;

    }


    /**
     * 模板中文 用于模板生成PDF时所用字体
     *
     * @param path 字体文件存储文件夹路径
     * @return
     * @throws com.lowagie.text.DocumentException
     * @throws IOException
     */
    public static ITextRenderer getRender(String path) throws com.lowagie.text.DocumentException, IOException {

        ITextRenderer render = new ITextRenderer();

        // 添加字体，以支持中文

        render.getFontResolver().addFont(path + "/fonts/arialuni.ttf", com.lowagie.text.pdf.BaseFont.IDENTITY_H, com.lowagie.text.pdf.BaseFont.NOT_EMBEDDED);

        // 微软雅黑
        render.getFontResolver().addFont(path + "/fonts/msyh.ttf", com.lowagie.text.pdf.BaseFont.IDENTITY_H, com.lowagie.text.pdf.BaseFont.NOT_EMBEDDED);

        return render;

    }

    /**
     * 中文字体
     * 注: 用于生成需要中文的PDF 否则中文将不显示
     */
    public static final class ChinaFont implements FontProvider {

        private int fontSize = 12;

        private int fontWeight = Font.NORMAL;

        ChinaFont() {
        }

        ChinaFont(int fontSize, int fontWeight) {
            this.fontSize = fontSize;
            this.fontWeight = fontWeight;
        }

        ChinaFont(int fontWeight) {
            this.fontWeight = fontWeight;
        }

        @Override
        public boolean isRegistered(String s) {
            return false;
        }

        @Override
        public Font getFont(String s, String s1, boolean b, float v, int i, BaseColor baseColor) {

            BaseFont baseFont = null;
            try {

                // 可用下载的字体
                baseFont = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);

            } catch (Exception e) {
                e.printStackTrace();
            }

            Font font = new Font(baseFont, fontSize, fontWeight);

            return font;
        }
    }


    /**
     * PDF 转 长图片 (多页PDF转1张图片)
     *
     * @param pdfPath
     * @param outPath
     */
    public static boolean pdfToPng(String pdfPath, String outPath) {

        try {

            File file = new File(pdfPath);
            if (!file.exists()) {
                log.warn("file is not exists: " + pdfPath);
                return false;
            }

            File outFile = new File(outPath);

            outFile.getParentFile().mkdirs();

            PDDocument pdDocument = PDDocument.load(file);

            PDFRenderer pdfRenderer = new PDFRenderer(pdDocument);
            int pages = pdDocument.getNumberOfPages();

            int width = 0;
            int height = 0;

            java.util.List<Integer> heights = new ArrayList<>();

            List<int[]> imgRgb = new ArrayList<>();

            for (int i = 0; i < pages; i++) {

                // dpi: 200 清晰度
                BufferedImage bufferedImage = pdfRenderer.renderImageWithDPI(i, 200);

                if (i == 0) {
                    width = bufferedImage.getWidth();
                }

                height += bufferedImage.getHeight();

                heights.add(bufferedImage.getHeight());

                int width_ = bufferedImage.getWidth(),
                        height_ = bufferedImage.getHeight();

                imgRgb.add(bufferedImage.getRGB(0, 0,
                        width_,
                        height_, new int[width_ * height_],
                        0, width_));
            }

            // 创建长图片 对象
            BufferedImage result = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB_PRE);

            int offsetHeight = 0;
            for (int i = 0; i < pages; i++) {

                int height_ = heights.get(i);

                if (i != 0) {
                    offsetHeight += height_;
                }

                // 写入流
                result.setRGB(0, offsetHeight, width,
                        height_, imgRgb.get(i), 0, width);

            }

            boolean flag = ImageIO.write(result, "png", new File(outPath));

            log.info("out pdf img print: " + flag);

            return flag;

        } catch (Exception e) {
            log.error("create png out error", e);
        }

        return false;
    }

    public static String imgToBase64(File imgFile) {

        try (
                FileInputStream inputStream = new FileInputStream(imgFile);
        ) {

            byte[] bytes = new byte[inputStream.available()];

            inputStream.read(bytes);

            String data = Base64Encoder.encode(bytes);

            if (StringUtils.isEmpty(data)) {
                return null;
            }

            return "data:image/jpg;base64," + data;

        } catch (Exception e) {
            log.error("img to base64 out error", e);
        }
        return null;

    }

    public static void main(String[] args) throws Exception {

        Map<String, Object> map = new HashMap<>();
        map.put("a", "ASDHSAJHKSA");
        map.put("b", "撒大年纪大四点八三");
        map.put("datas", new String[]{"asdsa", "撒大苏打", "4564asd撒大"});
        map.put("img", imgToBase64(new File("C:\\Users\\76167\\Desktop\\文档数据\\test\\pdf\\img\\东岩合伙人计划2020.png")));

        getFreemarkerConfig("C:\\Users\\76167\\Desktop\\文档数据\\test\\pdf\\template");
        generateToFile("C:\\Users\\76167\\Desktop\\文档数据\\test\\pdf\\template",
                "test_img.ftl", "C:\\Users\\76167\\Desktop\\文档数据\\test\\pdf\\img",
                map,
                "C:\\Users\\76167\\Desktop\\文档数据\\test\\pdf\\test.pdf");

    }
}
